package com.nstc.sftpExchange.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ssh.Sftp;
import com.jcraft.jsch.ChannelSftp;
import com.nstc.sftpExchange.config.sftp.ChannelCallback;
import com.nstc.sftpExchange.config.sftp.SftpConfigProperties;
import com.nstc.sftpExchange.config.sftp.SftpTemplate;
import com.nstc.sftpExchange.constants.Constants;
import com.nstc.sftpExchange.util.SpringBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SftpService {

    private final Map<String, SftpConfigProperties.SftpConfig> hostToConfig;

    private final SpringBean springBean;

    @Autowired
    public SftpService(SpringBean springBean,
                       SftpConfigProperties sftpConfigProperties) {
        this.springBean = springBean;
        List<SftpConfigProperties.SftpConfig> sftp = sftpConfigProperties.getSftp();
        this.hostToConfig = sftp.stream()
                .collect(Collectors.toMap(
                        SftpConfigProperties.SftpConfig::getName,
                        config -> config,
                        (existing, replacement) -> existing
                ));
    }

    public List<File> doSftpDownload(String name, String remoteFile, String downloadFileName) {
        return downloadFile(
                getBusinessTypeBean(name),
                remoteFile,
                getConfigProperties(name).getDownloadDir(),
                downloadFileName
        );
    }

    public void doSftpUploadFile(String name, String remoteDir, File localFile) {
        SftpTemplate sftpTemplate = getBusinessTypeBean(name);
        uploadFile(sftpTemplate, remoteDir, localFile);
    }

    private SftpTemplate getBusinessTypeBean(String name) {
        return this.springBean.getBean(name, SftpTemplate.class);
    }

    private SftpConfigProperties.SftpConfig getConfigProperties(String name) {
        return this.hostToConfig.get(name);
    }

    private List<File> downloadFile(SftpTemplate sftpTemplate, String remoteFie, String localPath, String downloadFileName) {
        return sftpTemplate.execute(channelSftp -> {
            List<File> downLoadFiles = new ArrayList<>();
            try {
                String fileName = FileUtil.getName(remoteFie);
                File localFile = new File(localPath, downloadFileName);
                log.info("sftp文件名：{}，下载本地文件名：{}", fileName, localFile);
                channelSftp.getChannelSftp().download(remoteFie, localFile);
                downLoadFiles.add(localFile);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return downLoadFiles;
        });
    }

    private List<File> downloadFile(SftpTemplate sftpTemplate, SftpConfigProperties.SftpConfig sftpConfig, String remoteDir, String subFix) {
        return sftpTemplate.execute(channelSftp -> {
            List<File> downLoadFiles = new ArrayList<>();
            try {
                Vector<ChannelSftp.LsEntry> targetFiles = channelSftp.getChannelSftp().getClient().ls(remoteDir);
                if (CollectionUtil.isEmpty(targetFiles)) {
                    return downLoadFiles;
                }
                for (ChannelSftp.LsEntry e : targetFiles) {
                    if (!e.getAttrs().isDir() && subFix.equalsIgnoreCase(FilenameUtils.getExtension(e.getFilename()))) {
                        File targetFile = new File(remoteDir, e.getFilename());
                        File localFile = new File(sftpConfig.getDownloadDir(), e.getFilename());
                        if (!localFile.getParentFile().exists()) {
                            //创建父目录
                            FileUtil.mkdir(localFile.getParentFile());
                        }
                        if (localFile.exists()) {
                            FileUtil.del(localFile);
                        }
                        String remoteFilePath = FilenameUtils.normalize(targetFile.getPath(), true);
                        String localPath = FilenameUtils.normalize(localFile.getAbsolutePath(), true);
                        channelSftp.getChannelSftp().get(remoteFilePath, localPath);
                        downLoadFiles.add(localFile);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return downLoadFiles;
        });
    }

    private void uploadFile(SftpTemplate sftpTemplate, String remoteDir, File localFile) {
        sftpTemplate.execute((ChannelCallback<Void>) channelSftp -> {
            try {
                log.info("上传文件名：{}", localFile.getName());
                Sftp sftpClient = channelSftp.getSftpClient();
                if (!remoteDirExists(sftpClient, remoteDir)) {
                    mkdirs(sftpClient, remoteDir);
                }
                String tempFilePath = FilenameUtils.normalize(remoteDir + File.separator + localFile.getName() + Constants.TEMP_SUB_FIX, true);
                String realFilePath = FilenameUtils.normalize(remoteDir + File.separator + localFile.getName(), true);
                log.debug("src:{},tempFilePath:{},realFilePath:{}", localFile.getAbsolutePath(), tempFilePath, realFilePath);

                if (localFile.length() > 0) {
                    sftpClient.put(localFile.getAbsolutePath(), tempFilePath, Sftp.Mode.RESUME);
                } else {
                    sftpClient.put(localFile.getAbsolutePath(), tempFilePath, Sftp.Mode.RESUME);
                }
                //上传成功后，去掉.temp扩展名
                sftpClient.getClient().rename(tempFilePath, realFilePath);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return null;
        });
    }

    public boolean remoteDirExists(Sftp sftpClient, String remoteDir) {
        boolean exist;
        try {
            sftpClient.cd(remoteDir);
            exist = true;
        } catch (Exception e) {
            exist = false;
        }
        return exist;

    }

    public void mkdirs(Sftp sftpClient, String dir) {
        try {
            if (StringUtils.isNotEmpty(dir)) {
                String remoteDir = FilenameUtils.normalize(dir, true);
                String[] folders = StringUtils.split(remoteDir, "/");
                String tempPath = "";
                for (String folder : folders) {
                    if (StringUtils.isNotEmpty(folder)) {
                        tempPath = tempPath + "/" + folder;
                        sftpClient.cd(tempPath);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void deleteLocalFile(List<File> files){
        for (File file : files) {
            FileUtil.del(file);
        }
    }
}
